/*
 * Copyright (c) [2020] Zhang Yansen.All rights reserved.
 *
 * with-function is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

import { useList, compose } from './utils';

/**
 * withFunction
 * 使用函数式的写法, 写Class组件
 * 
 */
export default function withFunction(Component) {
  return function (setup) {
    if (typeof setup !== 'function') {
      throw new Error("[useFunction] 1st param must be function")
    }
  
    // 这几个生命周期支持多函数绑定
    const [mountedFuns, appendMountedFuns] = useList()
    const [updateFuns, appendUpdateFuns] = useList()
    const [catchFuns, appendCatchFuns] = useList()
    const [unmountFuns, appendUnmountFuns] = useList()
  
    class _WrappedComponent extends Component {
      constructor(props) {
        super(props)
  
        this.state = {}
  
        // 默认使用 函数名 作为组件名称
        if (setup.name && typeof setup.name === 'string') {
          const startUpper = setup.name.charCodeAt(0) >= 64 && setup.name.charCodeAt(0) <= 90
          if (startUpper) {
            _WrappedComponent.displayName = setup.name
          }
        }
  
        // setup 函数必须返回 render
        const render = setup.call(this,
          {
            forceUpdate: this.forceUpdate.bind(this),
            setState: this.setState.bind(this),
  
            // shouldComponentUpdate 只能有一个
            shouldComponentUpdate: f => {
              if (typeof f === 'function') {
                _WrappedComponent.prototype.shouldComponentUpdate = f.bind(this)
              }
            },
  
            // getSnapshotBeforeUpdate 只能有一个
            getSnapshotBeforeUpdate: f => {
              if (typeof f === 'function') {
                _WrappedComponent.prototype.getSnapshotBeforeUpdate = f.bind(this)
              }
            },
  
            // 其余生命周期可以绑定多个
            componentDidMount: appendMountedFuns,
            componentDidUpdate: appendUpdateFuns,
            componentDidCatch: appendCatchFuns,
            componentWillUnmount: appendUnmountFuns,
  
            // 其他
            displayName: name => _WrappedComponent.displayName = name,
            defaultProps: props => _WrappedComponent.defaultProps = props,
          },
          this, // 支持箭头函数访问 this
        )
  
        if (mountedFuns.length > 0) {
          _WrappedComponent.prototype.componentDidMount = compose(mountedFuns, this)
        }
        if (updateFuns.length > 0) {
          _WrappedComponent.prototype.componentDidUpdate = compose(updateFuns, this)
        }
        if (catchFuns.length > 0) {
          _WrappedComponent.prototype.componentDidCatch = compose(catchFuns, this)
        }
        if (unmountFuns.length > 0) {
          _WrappedComponent.prototype.componentWillUnmount = compose(unmountFuns, this)
        }
        _WrappedComponent.prototype.render = render.bind(this)
      }
    }
  
    return _WrappedComponent
  }  
}
